// 一些实用方法
import dayjs from 'dayjs';
import { COS_CONF } from '../constants/common';

// 格式化相关

/**
 * 格式化小数
 * @param {*} num 
 * @param {*} decimals 
 * @param {*} keeptype 
 */
const formatDecimal = (num, decimals = 2, keeptype = true) => {
    const _value = Math.abs(num) < Number.EPSILON ? 0 : Number(Math.round(Number(num + 'e' + decimals)) + 'e-' + decimals);
    return keeptype ? _value : keeptype === undefined ? _value.toString() : _value.toFixed(decimals);
};

/**
 * 格式化输入数字
 * @param {String|Number} num 
 * @param {Number} decimals
 */
const formatInputDecimal = (num, decimals = 2) => {
    let fmv = formatDecimal(num, decimals);
    let val = num ? (num !== undefined && num !== null && num !== '' ? fmv : '') : num;
    if (val !== undefined && val !== null && val !== '' && /\.$/.test(`${num}`)) val += '.';
    if (num == '0.0') val = num;
    return isNaN(val) || val === undefined ? '' : val;
};

/**
 * 价格元转化为分
 * @param {String|Number} price
 * @param {Boolean} reverse 反向
 */
const formatPrice = (price, reverse = false) => {
    let fmv = formatDecimal(price, reverse ? 0 : 2);
    let val = price ? (price !== undefined && price !== null && price !== '' ? (reverse ? fmv / 100 : (fmv * 100).toFixed(0) * 1) : '') : price;
    if (val !== undefined && val !== null && val !== '' && /\.$/.test(`${price}`)) val += '.';
    if (price == '0.0') val = price;
    return isNaN(val) || val === undefined ? '' : val;
};

/**
 * 格式化时间
 * @param {Date|Number} date 时间
 * @param {String} format 格式
 */
const formatDate = (date, format = 'YYYY-MM-DD') => {
    return dayjs(date).format(format);
};

/**
 * 获取时长
 * @param {Number} timestamp 时间戳
 * @param {String} extTip 额外提示
 */
const getTimeDuration = (timestamp, extTip = '') => {
    const nowTimestamp = new Date().getTime();
    const len = nowTimestamp - timestamp;
    let unit = '秒';
    let result = len / 1000;
    if (result > 60) {
        result = result / 60;
        if (result > 60) {
            result = result / 60;
            if (result > 24) {
                result = result / 24;
                if (result > 30) {
                    return formatDate(timestamp, 'YYYY-MM-DD HH:mm:ss');
                }
                unit = '天';
            } else {
                unit = '小时';
            }
        } else {
            unit = '分钟';
        }
    }
    return `${parseInt(result)}${unit}${extTip}`;
};

/**
 * 获取开始结束时间
 * @param {Number} begin 开始时间
 * @param {Number} end 结束时间
 */
const getTimeBeginEnd = (begin, end) => {
    const now = Date.now();
    const nYear = new Date().getFullYear();
    const bYear = new Date(begin).getFullYear();
    const eYear = new Date(end).getFullYear();
    let str = '';
    if (begin > now) {
        str = `将于${formatDate(begin, (nYear == bYear ? '' : 'YYYY年') + 'MM月DD日 HH:mm')}开始`;
    } else if (end < now) {
        str = `活动已结束`;
    } else {
        str = `将于${formatDate(end, (nYear == eYear ? '' : 'YYYY年') + 'MM月DD日 HH:mm')}结束`;
    }
    return str;
};

/**
 * 获取开始结束时间戳
 * @param {Number} date 日期
 * @param {Boolean} end
 * @param {String} unit 单位
 */
const getDateTS = (date, end = false, unit = 'day') => {
    if (end) {
        return dayjs(date || undefined).endOf(unit).valueOf();
    }
    return dayjs(date || undefined).startOf(unit).valueOf();
};

/**
 * 比较两个时间的大小，返回是否第一个时间大于第二个时间
 * @param {Date} aTime 时间
 * @param {Date} bTime 时间
 */
const compareTimeValue = (aTime, bTime) => {
    return dayjs(aTime) > dayjs(bTime);
};

/**
 * 是否是有效时间
 * @param {Number} time 时间戳
 */
const isValidTime = (time) => {
    return compareTimeValue(time, dayjs());
};

// 验证相关

/**
 * 类型判断
 * @param 
 */
const isBoolean = b => (b === !!b);
const isString = s => (s === s + '');
const isNumber = n => (n === +n);
const isInteger = i => (Number.isInteger(i));
const isObject = o => (o === Object(o));
const isArray = a => {
    if (typeof Array.isArray === "function") {
        return Array.isArray(a)
    } else {
        return Object.prototype.toString.call(a) === "[object Array]"
    }
};
const isEmpty = (o) => {
    if (isString(o) || isArray(o)) {
        return o.length === 0
    } else if (isNumber(o) || isBoolean(o) || isInteger(o)) {
        return (o + '').length === 0
    } else if (isObject(o)) {
        return Object.keys(o).length === 0
    }
    return false
};
const isFunction = (f) => {
    return typeof f === 'function';
};

/**
 * 验证手机号是否正确
 * @param {Number | String} num 手机号
 */
const isValidPhone = (num) => {
    const reg = /^(((13[0-9])|(14[0-9])|(15[0-9])|(16[0-9])|(17[0-9])|(18[0-9])|(19[0-9]))\d{8})$/;
    if (!num) {
        return false;
    }
    if (!reg.test(num + '')) {
        return false;
    }
    return true;
};
/**
 * 验证电话是否正确
 * @param {Number | String} num 手机号
 */
const isValidTel = (num) => {
    const reg = /^((d{3,4})|d{3,4}-|s)?d{7,14}$/;
    if (!num) {
        return false;
    }
    if (!reg.test(num + '')) {
        return false;
    }
    return true;
};

/**
 * 校验邮箱
 * @param {String} email 邮箱
 */
const isValidMail = (email) => {
    const reg = new RegExp('^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$');
    return reg.test(email);
};

// 一些方法合集

/**
 * 参数转对象url
 * @param {String} url 地址链接
 */
const urlParam2Obj = (url) => {
    url = decodeURIComponent(url);
    let hash;
    let json = {};
    let hashes = url.slice(url.indexOf('?') + 1).split('&');
    for (var i = 0; i < hashes.length; i++) {
        hash = hashes[i].split('=');
        json[hash[0]] = hash[1];
    }
    return json;
};

/**
 * 获取 url 的参数值
 * @param {String} url 地址链接
 * @param {String} name 参数名
 */
const getUrlParam = (url, name) => {
    var reg = new RegExp('(^|&|/?)' + name + '=([^&|/?]*)(&|/?|$)', 'i');
    var r = url.substr(1).match(reg);
    if (r != null) {
        return r[2] || '';
    }
    return '';
};

/**
 * 设置 url 参数
 * @param {String} url 
 * @param {Object} param 
 */
const setUrlParam = (url, param) => {
    let urlArr = url.split('?');
    param = urlArr[1] ? Object.assign(urlParam2Obj(urlArr[1]), param) : param;
    let paramStr = '';
    for (var k in param) {
        let value = param[k] !== undefined ? param[k] : '';
        paramStr += `&${k}=${encodeURIComponent(value)}`;
    }
    paramStr = paramStr.substring(1);
    url = paramStr ? `${urlArr[0]}?${paramStr}` : url;
    return url;
};

// 随机字符串
const randomString = (e) => {
    e = e || 32;
    let t = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678',
        a = t.length,
        n = '';
    for (let i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a));
    return n;
};

/**
 * 对象转成数组
 * @param {Object} obj 
 */
const obj2Arr = (obj, key = 'value', value = 'name') => {
    let arr = [];
    for (let i in obj) {
        const o = {};
        o[key] = i;
        o[value] = obj[i];
        arr.push(o);
    }
    return arr.sort((a, b) => a[key] - b[key]);
};

/**
 * 数组转对象
 * @param arr
 * @param keyProp
 * @returns {{}}
 */
const arr2Obj = (arr, keyProp, valueProp) => {
    let res = {};

    (arr || []).forEach((item, index) => {
        if (keyProp && Object.hasOwnProperty.call(item, keyProp)) {
            res[item[keyProp]] = valueProp ? item[valueProp] : item
        } else if (!keyProp) {
            if (!isObject(item)) {
                res[item] = valueProp ? item[valueProp] : item
            } else {
                res[`${index}`] = valueProp ? item[valueProp] : item
            }
        }
    })

    return res
}

/**
 * 交换数组元素位置
 * @param {Array} arr 
 * @param {number} idx1 
 * @param {number} idx2 
 */
const swapArr = (arr, idx1, idx2) => {
    arr[idx1] = arr.splice(idx2, 1, arr[idx1])[0];
    return arr;
};

/**
 * 过滤掉空数据
 * @param {Object} obj 
 */
const setEmptyObj = (obj) => {
    for (let i in obj) {
        let v = obj[i];
        if (v === '' || v === null || v === undefined || isEmpty(v)) {
            delete obj[i];
        }
    }
    return obj
};

/**
 * 过滤出keys(有效的键组成的对象)
 * @param {Object| number} o 
 * @param {...any} keys
 */
const pick = (o, ...keys) => {
    let result = {};
    if (o) {
        if (Array.isArray(o)) {
            return o.map(o => pick.apply(null, [o].concat(keys)));
        } else if (isObject(o)) {
            for (let k of keys) {
                if (o[k]) {
                    result[k] = o[k];
                }
            }
        }
    }
    return result;
};

/**
 * 数组groupBy
 * @param {Array} array 
 * @param {Function | String} fn
 * @returns 
 */
const groupBy = (array, fn) => {
    const groups = {};
    array.forEach((item) => {
        const group = JSON.stringify(isFunction(fn) ? fn(item) : item[fn] );
        groups[group] = groups[group] || [];
        groups[group].push(item);
    });
    return Object.keys(groups).map(group => groups[group]);
};

/**
 * 获取图片完整路径
 * @param {String} url 
 */
const getPicFullPath = (url) => {
    console.log('getPicFullPath url=>', url)
    return !url || /https?\:/.test(url) ? url : `${COS_CONF.path}/${url}`;
};

/**
 * 获取scene对象
 * @param {Object} options 
 */
const getQRcodeScene = (options) => {
    let scene = {};
    if (options.scene) {
        scene = urlParam2Obj(options.scene);
    }
    return scene;
};

/**
 * 省市区code转地址
 */
const areaCode2Str = (areaInfo, code) => {
    const { province_list, city_list, county_list } = areaInfo;
    let co_str = county_list[code];
    let ci_str = city_list[code.substr(0, 4) + '00'];
    let po_str = province_list[code.substr(0, 2) + '0000'];
    return `${po_str}${po_str !== ci_str ? ci_str : ''}${co_str}`;
};

/**
 * 最大整型
 */
const getMaxNumber = () => {
    return Number.MAX_SAFE_INTEGER;
};

/* 深克隆 */
const deepClone = (obj) => {
    if (obj === null) return null
    const clone = Object.assign({}, obj)
    Object.keys(clone).forEach(
        key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
    )
    return Array.isArray(obj) && obj.length
        ? (clone.length = obj.length) && Array.from(clone)
        : Array.isArray(obj)
            ? Array.from(obj)
            : clone
};

module.exports = {
    formatDecimal,
    formatInputDecimal,
    formatDate,
    formatPrice,
    getTimeDuration,
    getTimeBeginEnd,
    compareTimeValue,
    isValidTime,
    getDateTS,
    isString,
    isNumber,
    isInteger,
    isObject,
    isArray,
    isEmpty,
    isFunction,
    isValidPhone,
    isValidTel,
    isValidMail,
    urlParam2Obj,
    getUrlParam,
    setUrlParam,
    randomString,
    obj2Arr,
    arr2Obj,
    swapArr,
    setEmptyObj,
    pick,
    groupBy,
    getPicFullPath,
    getQRcodeScene,
    areaCode2Str,
    getMaxNumber,
    deepClone,
};
